﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using RayDen.Library.Components;
using RayDen.Library.Data.Xml;
using RayDen.Library.Entity.Frames;
using RayDen.RayEngine;

namespace UITools
{
    public partial class AppForm : Form
    {
        protected bool rendering;
        protected FrameController frameController;
        protected RendererController renderController;

        public AppForm()
        {
            InitializeComponent();
            this.frameController = new FrameController();
            this.renderController = new RendererController();
            Directory.SetCurrentDirectory(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location));
            GlobalConfiguration.Instance.OpenConfig(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Global.Config.xml");
            renderPropertyGrid.SelectedObject = GlobalConfiguration.Instance;
        }

        protected override void OnClosed(EventArgs e)
        {
            this.renderController.RenderConfig.Dispose();
            base.OnClosed(e);
        }

        private void StartRenderFrame()
        {
            rendering = true;
            this.renderController.Start();
        }

        private void InterrupRendering()
        {
            rendering = false;
            this.renderController.Interrupt();
        }

        private async void btnRender_Click(object sender, EventArgs e)
        {
            if (frameController.Frame != null)
            {

                this.btnRender.Enabled = false;
                var renderTask = Task.Factory.StartNew(this.StartRenderFrame);
                await renderTask;
                this.btnRender.Enabled = true;
                this.Text = "Rendering started";
            }
        }

        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            this.InterrupRendering();
            this.Text = "Rendering interrupted";
        }

        private void openFrameToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                frameController.Open(openFileDialog1.FileName);
                frameController.Frame["ImageWidth"] = ctlCanvas.ClientSize.Width;
                frameController.Frame["ImageHeight"] = ctlCanvas.ClientSize.Height;

                this.renderController.SetupFrame(frameController.Frame);
                this.BindSceneGraph();
                this.framePropertyGrid.SelectedObject = frameController.Frame;
            }
        }

        private void BindSceneGraph()
        {
            var sg = EngineConfiguration;
            this.sceneGraphPropertyGrid.SelectedObject = sg.Scene;
            this.lstSceneGraph.Items.AddRange(EngineConfiguration.Scene.Meshes.Select(item=>new ListViewItem()
                {
                    Text = "Mesh_" + item.MeshName,                    
                    ForeColor = Color.Red
                    //Group = "Geometry",
                    
            
                }).ToArray());

            //this.lstMaterials.ValueMember = "";
            this.lstMaterials.DisplayMember = "Name";
            this.lstMaterials.Items.AddRange((sg.Scene.MatLib as OptimizedBsdfLibrary).Materials.ToArray());

            
        }

        private RayEngineConfiguration EngineConfiguration
        {
            get
            {
                var sg = (this.renderController.RenderConfig as RayEngineConfiguration);
                return sg;
            }
        }

        private void ctlCanvas_Paint(object sender, PaintEventArgs e)
        {
            if (this.rendering)
            {
                var film = renderController.RenderConfig.GetImagePlane();
                if (film != null)
                {
                    film.UpdateScreenBuffer();
                    var pixels = film.GetScreenBuffer();
                    if (ctlCanvas.Image == null)
                    {
                        ctlCanvas.Image = new Bitmap(renderController.RenderConfig.Width, renderController.RenderConfig.Height, e.Graphics);
                    }
                    var bmp = (Bitmap)ctlCanvas.Image;
                    var offset = 0;
                    for (int i = 0; i < renderController.RenderConfig.Height; i++)
                    {
                        for (int j = 0; j < renderController.RenderConfig.Width; j++, offset += 3)
                        {
                            var pix = Color.FromArgb((int)(255.0 * pixels[offset]), (int)(255.0 * pixels[offset + 1]),
                                                     (int)(255.0 * pixels[offset + 2]));
                            bmp.SetPixel(j, i, pix);
                        }
                    }
                    ctlCanvas.Invalidate();
                    lblStats.Text = renderController.RenderConfig.GetStats();
                }

            }
        }

        private void btnSaveImage_Click(object sender, EventArgs e)
        {
            if (this.ctlCanvas.Image != null && saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                this.renderController.RenderConfig.SaveImage(saveFileDialog1.FileName);
            }
        }

        private void openFrameSourceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                using (var frameFile = new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.Read))
                {
                    using (var reader = new StreamReader(frameFile))
                    {
                        var fsForm = new FramesourceForm() { Owner = this, FrameSource = reader.ReadToEnd(),Text = "Frame "+openFileDialog1.FileName };
                        fsForm.Show(this);
                    }
                }
            }
        }

        internal void SetupFrame(string p)
        {
            lblStats.Text = "Start loading frame";
            frameController.FrameSource = p;
            frameController.Frame["ImageWidth"] = ctlCanvas.ClientSize.Width;
            frameController.Frame["ImageHeight"] = ctlCanvas.ClientSize.Height;

            this.renderController.SetupFrame(frameController.Frame);
            this.BindSceneGraph();
            this.framePropertyGrid.SelectedObject = frameController.Frame;
            lblStats.Text = "Loading complete.";

        }

        private void lstMaterials_SelectedIndexChanged(object sender, EventArgs e)
        {
            var mIndex = lstMaterials.SelectedIndex;
            if (mIndex >= 0)
            {
                /*
                var mat = EngineConfiguration.Scene.MatLib.Materials.ToArray()[mIndex];
                bsdfPropertyGrid.SelectedObject = new
                    {
                        Type = mat.First.BrdfName,
                        Name = mat.First.MaterialData.MaterialName,
                        Alpha = mat.First.MaterialData.Alpha != null ? mat.First.MaterialData.Alpha.Name : string.Empty,
                        BumpMap = mat.First.MaterialData.BumpMap != null ? mat.First.MaterialData.BumpMap.Name : string.Empty,
                        Diffuse = mat.First.MData.Diffuse != null ? mat.First.MData.Diffuse.Name : string.Empty,
                        NormalMap = mat.First.MaterialData.NormalMap != null ? mat.First.MaterialData.NormalMap.Name : string.Empty,                      
                    };
                 */ 

            }

        }

        private void lstSceneGraph_SelectedIndexChanged(object sender, EventArgs e)
        {
            var index = lstSceneGraph.SelectedIndices;
        }

        private void lstSceneGraph_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            var index = e.ItemIndex;
            sceneGraphPropertyGrid.SelectedObject = EngineConfiguration.Scene.Meshes[index];

        }

        private void tabControl2_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (EngineConfiguration.Scene != null)
                sceneGraphPropertyGrid.SelectedObject = EngineConfiguration.Scene;
        }

        private void logToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void texturesManagerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var tv = new TextureViewForm() { Owner = this };
            tv.Show(this);
        }
    }
}
